//
//  Model3D.cpp
//  C3W_Demo_By_Fan
//
//  Created by 范静涛 on 2024/7/21.
//

//------------------------------------------------------------------------------
//【文件名】Model3D.cpp
//【功能模块和目的】三维模型类实现
//【开发者及日期】范静涛 2024/7/23
//【更改记录】2024/8/12 范静涛 修正了部分成员函数形参缩写为完整单词
//------------------------------------------------------------------------------

#include "Model3D.hpp"
//Face3D类所属头文件
#include "Face3D.hpp"
//Line3D类所属头文件
#include "Line3D.hpp"
//Point3D类所属头文件
#include "Point3D.hpp"
//std::vector所属头文件
#include <vector>
//size_t所属头文件
#include <cstddef>
//std::shared_ptr类所属头文件
#include <memory>
//StringList类所属头文件
#include "StringList.hpp"
//std::vector操作所需算法头文件
#include <algorithm>
//std::vector操作所需仿函数头文件
#include <functional>

//------------------------------------------------------------------------------
//必要的构造、析构、赋值行为
//------------------------------------------------------------------------------

//函数名：Model3D
//功能：默认构造函数
//入口参数：无
//出口参数：无
//返回值：无
Model3D::Model3D(){
}
//------------------------------------------------------------------------------

//函数名：Model3D
//功能：带参构造函数。给定初始化所需Face3D和Line3D列表
//入口参数：const std::vector<Face3D>& vFaces, const std::vector<Line3D>& vLines
//出口参数：无
//返回值：无
Model3D::Model3D
(const std::vector<Face3D>& vFaces, const std::vector<Line3D>& vLines){
    //添加面
    for (auto Face : vFaces) {
        AppendFace(Face);
    }
    //逐一添加线
    for (auto Line : vLines) {
        AppendLine(Line);
    }
}
//------------------------------------------------------------------------------

//函数名：Model3D
//功能：拷贝构造函数。shared_ptr不需要深拷贝
//入口参数：const Model3D& Source
//出口参数：无
//返回值：无
Model3D::Model3D(const Model3D& Source){
    m_Faces        = Source.Faces;
    m_Lines        = Source.Lines;
    m_FaceCount    = Source.FaceCount;
    m_LineCount    = Source.LineCount;
    m_PointCount   = Source.PointCount;
    m_ElementCount = Source.ElementCount;
    m_Area         = Source.Area;
    m_Length       = Source.Length;
    m_BoundBox_X   = Source.m_BoundBox_X;
    m_BoundBox_Y   = Source.m_BoundBox_Y;
    m_BoundBox_Z   = Source.m_BoundBox_Z;
    m_BoundBox_Vol = Source.BoundBox_Vol;
    Name           = Source.Name;
    Comments       = Source.Comments;
}
//------------------------------------------------------------------------------

//函数名：operator=
//功能：赋值运算符overload。shared_ptr不需要深赋值
//入口参数：const Model3D& Source
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator=(const Model3D& Source){
    if (this != &Source) {
        m_Faces        = Source.Faces;
        m_Lines        = Source.Lines;
        m_FaceCount    = Source.FaceCount;
        m_LineCount    = Source.LineCount;
        m_ElementCount = Source.ElementCount;
        m_Area         = Source.Area;
        m_Length       = Source.Length;
        m_BoundBox_X   = Source.m_BoundBox_X;
        m_BoundBox_Y   = Source.m_BoundBox_Y;
        m_BoundBox_Z   = Source.m_BoundBox_Z;
        m_BoundBox_Vol = Source.BoundBox_Vol;
        Name           = Source.Name;
        Comments       = Source.Comments;
    }
    return *this;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//非静态Setter成员函数
//------------------------------------------------------------------------------

//函数名：AppendFace
//功能：添加一个指定的Face3D
//入口参数：const Face3D& AFace
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::AppendFace(const Face3D& AFace){
    //调用搜索指定Face3D的迭代器
    auto it = FindFaceIter(AFace);
    //找到指定面，返回false
    if (it != m_Faces.end()) {
        return false;
    }
    //新建并添加
    std::shared_ptr<Face3D>TempPtr{new Face3D{AFace}};
    m_Faces.push_back(TempPtr);
    //更新各种统计值
    m_FaceCount++;
    m_PointCount += 3;
    m_ElementCount++;
    m_Area += TempPtr->Area();
    CalcBoundBox();
    //返回true
    return true;
}
//------------------------------------------------------------------------------

//函数名：AppendFace
//功能：添加一个三点指定的Face3D
//入口参数：const Point3D& Point1, const Point3D& Point2, const Point3D& Point3
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::AppendFace
(const Point3D& Point1, const Point3D& Point2, const Point3D& Point3){
    return AppendFace(Face3D(Point1, Point2, Point3));
}
//------------------------------------------------------------------------------

//函数名：RemoveFace
//功能：删除一个指定的Face3D
//入口参数：const Face3D& AFace
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::RemoveFace(const Face3D& AFace){
    //调用搜索指定Face3D的迭代器
    auto it = FindFaceIter(AFace);
    //未找到，返回false
    if (it == m_Faces.end()) {
        return false;
    }
    //删除指定Face3D
    m_Faces.erase(it);
    //更新统计值
    m_FaceCount--;
    m_PointCount -= 3;
    m_ElementCount--;
    m_Area -= AFace.Area();
    CalcBoundBox();
    return true;
}
//------------------------------------------------------------------------------

//函数名：RemoveFace
//功能：三处一个三点指定的Face3D
//入口参数：const Point3D& Point1, const Point3D& Point2, const Point3D& Point3
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::RemoveFace
(const Point3D& Point1, const Point3D& Point2, const Point3D& Point3){
    return RemoveFace(Face3D(Point1, Point2, Point3));
}
//------------------------------------------------------------------------------

//函数名：ModifyFace
//功能：修改一个指定的Face3D
//入口参数：const Face3D& From,  const Face3D& To
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::ModifyFace(const Face3D& From,  const Face3D& To){
    //搜索From迭代器
    auto itFrom = FindFaceIter(From);
    //搜索To迭代器
    auto itTo   = FindFaceIter(To);
    //From不存在或To存在，返回false
    if (itFrom == m_Faces.end() || itTo != m_Faces.end()) {
        return false;
    }
    //更新
    *(*itFrom) = To;
    //更新统计值
    m_Area -= From.Area();
    m_Area += To.Area();
    CalcBoundBox();
    return true;
}
//------------------------------------------------------------------------------

//函数名：ModifyFace
//功能：修改一个指定的Face3D中的From点为To
//入口参数：const Face3D& AFace, const Point3D& From, const Point3D& To
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::ModifyFace
(const Face3D& AFace, const Point3D& From, const Point3D& To){
    //AFace中不存在From，返回false
    if (!AFace.Points.Exists(From)){
        return false;
    }
    //AFace中存在To，返回false
    if (AFace.Points.Exists(To)){
        return false;
    }
    //构建Face3D临时对象
    Face3D TempFace{AFace};
    //修改临时对象
    TempFace.ModifyPoint(From, To);
    //间接调用完成面修改
    return ModifyFace(AFace, TempFace);
}
//------------------------------------------------------------------------------

//函数名：ModifyFace
//功能：修改一个指定的Face3D中的Index指定点为To
//入口参数：const Face3D& AFace, size_t Index, const Point3D& To
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::ModifyFace(const Face3D& AFace, size_t Index, const Point3D& To){
    return ModifyFace(AFace, AFace.Points[Index], To);
}
//------------------------------------------------------------------------------

//函数名：ClearFaces
//功能：删除所有Face3D
//入口参数：无
//出口参数：无
//返回值：无
void Model3D::ClearFaces(){
    //删除所有
    m_Faces.clear();
    //更新统计值
    m_Area = 0.0;
    m_ElementCount -= m_FaceCount;
    m_PointCount -= 3* m_FaceCount;
    m_FaceCount = 0;
    CalcBoundBox();
}
//------------------------------------------------------------------------------

//函数名：AppendLine
//功能：添加一个指定的Line3D
//入口参数：const Line3D& ALine
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::AppendLine(const Line3D& ALine){
    //搜索指定Line3D迭代器
    auto it = FindLineIter(ALine);
    //找到，返回false
    if (it != m_Lines.end()) {
        return false;
    }
    //新建添加
    std::shared_ptr<Line3D>TempPtr{new Line3D{ALine}};
    m_Lines.push_back(TempPtr);
    //更新统计值
    m_LineCount++;
    m_PointCount += 2;
    m_ElementCount++;
    m_Length += TempPtr->Length();
    CalcBoundBox();
    //返回true
    return true;
}
//------------------------------------------------------------------------------

//函数名：AppendLine
//功能：添加一个两点指定的Line3D
//入口参数：const Point3D& Point1, const Point3D& Point2
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::AppendLine(const Point3D& Point1, const Point3D& Point2){
    return AppendLine(Line3D(Point1, Point2));
}
//------------------------------------------------------------------------------

//函数名：RemoveLine
//功能：删除一个Line3D
//入口参数：const Line3D& ALine
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::RemoveLine(const Line3D& ALine){
    //搜索指定Line3D迭代器
    auto it = FindLineIter(ALine);
    //没找到，返回false
    if (it == m_Lines.end()) {
        return false;
    }
    //删除
    m_Lines.erase(it);
    //更新统计值
    m_LineCount--;
    m_PointCount -= 2;
    m_ElementCount--;
    m_Length -= ALine.Length();
    CalcBoundBox();
    //返回true
    return true;
}
//------------------------------------------------------------------------------

//函数名：RemoveLine
//功能：删除一个两点指定的Line3D
//入口参数：const Point3D& Point1, const Point3D& Point2
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::RemoveLine(const Point3D& Point1, const Point3D& Point2){
    return RemoveLine(Line3D(Point1, Point2));
}
//------------------------------------------------------------------------------

//函数名：ModifyLine
//功能：修改一个Line3D
//入口参数：const Line3D& From,  const Line3D& To
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::ModifyLine(const Line3D& From,  const Line3D& To){
    //搜索From迭代器
    auto itFrom = FindLineIter(From);
    //搜索To迭代器
    auto itTo   = FindLineIter(To);
    //不存在From或存在To，返回false
    if (itFrom == m_Lines.end() || itTo != m_Lines.end()) {
        return false;
    }
    //更新Line3D
    *(*itFrom) = To;
    //更新统计值
    m_Length -= From.Length();
    m_Length += To.Length();
    CalcBoundBox();
    return true;
}
//------------------------------------------------------------------------------

//函数名：ModifyLine
//功能：修改一个指定Line3D上的From点为To点
//入口参数：const Line3D& ALine, const Point3D& From, const Point3D& To
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::ModifyLine
(const Line3D& ALine, const Point3D& From, const Point3D& To){
    //Aline上不存在From点，返回fasle
    if (!ALine.Points.Exists(From)){
        return false;
    }
    //Aline上存在To点，返回fasle
    if (ALine.Points.Exists(To)){
        return false;
    }
    //构建临时Line3D对象
    Line3D TempLine{ALine};
    //修改临时对象
    TempLine.ModifyPoint(From, To);
    //间接调用完成修改
    return ModifyLine(ALine, TempLine);
}
//------------------------------------------------------------------------------

//函数名：ModifyLine
//功能：修改一个指定的Line3D中的Index指定点为To
//入口参数：const Line3D& ALine, size_t Index, const Point3D& To
//出口参数：无
//返回值：成功返回true，否则返回false
bool Model3D::ModifyLine(const Line3D& ALine, size_t Index, const Point3D& To){
    return ModifyLine(ALine, ALine.Points[Index], To);
}
//------------------------------------------------------------------------------

//函数名：ClearLines
//功能：删除所有Line3D
//入口参数：无
//出口参数：无
//返回值：无
void Model3D::ClearLines(){
    //删除所有
    m_Lines.clear();
    //更新统计值
    m_Length = 0.0;
    m_ElementCount -= m_LineCount;
    m_PointCount -= 2 * m_LineCount;
    m_LineCount = 0;
    CalcBoundBox();
}
//------------------------------------------------------------------------------

//函数名：Clear
//功能：删除所有Face3D和Line3D
//入口参数：无
//出口参数：无
//返回值：无
void Model3D::Clear(){
    ClearFaces();
    ClearLines();
}
//------------------------------------------------------------------------------

//函数名：operator+=
//功能：模型合并，自赋值运算符overload
//入口参数：const Model3D& AModel
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator+=(const Model3D& AModel){
    //通过添加Face3D实现，不会有重复
    for (auto Face : AModel.Faces) {
        AppendFace(*Face);
    }
    //通过添加Line3D实现，不会有重复
    for (auto Line : AModel.Lines) {
        AppendLine(*Line);
    }
    return *this;
}
//------------------------------------------------------------------------------

//函数名：operator+=
//功能：模型合并Face3D，自赋值运算符overload
//入口参数：const std::vector<Face3D>& vFaces
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator+=(const std::vector<Face3D>& Faces){
    //通过添加Face3D实现，不会有重复
    for (auto Face : Faces) {
        AppendFace(Face);
    }
    return *this;
}
//------------------------------------------------------------------------------

//函数名：operator+=
//功能：模型合并Line3D，自赋值运算符overload
//入口参数：const std::vector<Line3D>& vLines
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator+=(const std::vector<Line3D>& Lines){
    //通过添加Line3D实现，不会有重复
    for (auto Line : Lines) {
        AppendLine(Line);
    }
    return *this;
}
//------------------------------------------------------------------------------

//函数名：operator-=
//功能：模型移除，自赋值运算符overload
//入口参数：const Model3D& AModel
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator-=(const Model3D& AModel){
    //通过删除Face3D实现
    for (auto Face : AModel.Faces) {
        RemoveFace(*Face);
    }
    //通过删除Line3D实现
    for (auto Line : AModel.Lines) {
        RemoveLine(*Line);
    }
    return *this;
}
//------------------------------------------------------------------------------

//函数名：operator-=
//功能：模型移除Face3D，自赋值运算符overload
//入口参数：const std::vector<Face3D>& vFaces
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator-=(const std::vector<Face3D>& Faces){
    //通过删除Face3D实现
    for (auto Face : Faces) {
        RemoveFace(Face);
    }
    return *this;
}
//------------------------------------------------------------------------------

//函数名：operator-=
//功能：模型移除Line3D，自赋值运算符overload
//入口参数：
//出口参数：无
//返回值：模型自身的引用
Model3D& Model3D::operator-=(const std::vector<Line3D>& Lines){
    //通过删除Line3D实现
    for (auto Line : Lines) {
        RemoveLine(Line);
    }
    return *this;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//非静态Getter成员函数：需检查所有Getter是否有后置const
//------------------------------------------------------------------------------

//函数名：operator+ const
//功能：模型合并，运算符overload
//入口参数：const Model3D& AModel
//出口参数：无
//返回值：合并后新模型
Model3D Model3D::operator+(const Model3D& AModel) const{
    Model3D Res{*this};
    Res += AModel;
    return Res;
}
//------------------------------------------------------------------------------

//函数名：operator+ const
//功能：模型合并Face3D，运算符overload
//入口参数：const std::vector<Face3D>& vFaces
//出口参数：无
//返回值：合并后新模型
Model3D Model3D::operator+(const std::vector<Face3D>& Faces) const{
    Model3D Res{*this};
    Res += Faces;
    return Res;
}
//------------------------------------------------------------------------------

//函数名：operator+ const
//功能：模型合并Line3D，运算符overload
//入口参数：const std::vector<Line3D>& vLines
//出口参数：无
//返回值：合并后新模型
Model3D Model3D::operator+(const std::vector<Line3D>& Lines) const{
    Model3D Res{*this};
    Res += Lines;
    return Res;
}
//------------------------------------------------------------------------------

//函数名：operator- const
//功能：模型移除，运算符overload
//入口参数：const Model3D& AModel
//出口参数：无
//返回值：移除后新模型
Model3D Model3D::operator-(const Model3D& AModel) const{
    Model3D Res{*this};
    Res -= AModel;
    return Res;
}
//------------------------------------------------------------------------------

//函数名：operator- const
//功能：模型移除Face3D，运算符overload
//入口参数：const std::vector<Face3D>& vFaces
//出口参数：无
//返回值：移除后新模型
Model3D Model3D::operator-(const std::vector<Face3D>& Faces) const{
    Model3D Res{*this};
    Res -= Faces;
    return Res;
}
//------------------------------------------------------------------------------

//函数名：operator- const
//功能：模型移除Line3D，运算符overload
//入口参数：const std::vector<Line3D>& vLines
//出口参数：无
//返回值：移除后新模型
Model3D Model3D::operator-(const std::vector<Line3D>& Lines) const{
    Model3D Res{*this};
    Res -= Lines;
    return Res;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//私有 非静态Setter成员函数
//------------------------------------------------------------------------------

//函数名：FindFaceIter
//功能：指定Face3D迭代器搜索
//入口参数：const Face3D& AFace
//出口参数：无
//返回值：找到返回具体迭代器，未找到返回尾迭代器
std::vector<std::shared_ptr<Face3D>>::iterator Model3D::FindFaceIter
(const Face3D& AFace){
    //Lambda表达式
    auto Finder =
        [&AFace](std::shared_ptr<Face3D> ptr)->bool{return *ptr == AFace;};
    //执行搜索
    auto it = find_if(m_Faces.begin(), m_Faces.end(), Finder);
    return it;
}
//------------------------------------------------------------------------------

//函数名：FindLineIter
//功能：指定Line3D迭代器搜索
//入口参数：
//出口参数：无
//返回值：找到返回具体迭代器，未找到返回尾迭代器
std::vector<std::shared_ptr<Line3D>>::iterator Model3D::FindLineIter
(const Line3D& ALine){
    //Lambda表达式
    auto Finder =
        [&ALine](std::shared_ptr<Line3D>& ptr)->bool{return *ptr == ALine;};
    //执行搜索
    auto it = find_if(m_Lines.begin(), m_Lines.end(), Finder);
    return it;
}
//------------------------------------------------------------------------------

//函数名：CalcBoundBox
//功能：计算更新包围盒
//入口参数：无
//出口参数：无
//返回值：无
void Model3D::CalcBoundBox(){
    //没有点，包围盒边长及体积为0
    if (FaceCount + LineCount == 0){
        m_BoundBox_X   = 0.0;
        m_BoundBox_Y   = 0.0;
        m_BoundBox_Z   = 0.0;
        m_BoundBox_Vol = 0.0;
        return;
    }
    //设定包围盒所有坐标最小值和最大值
    double Min_X;
    double Min_Y;
    double Min_Z;
    double Max_X;
    double Max_Y;
    double Max_Z;
    if (FaceCount == 0) {
        Min_X = Lines[0]->Points[0].X;
        Min_Y = Lines[0]->Points[0].Y;
        Min_Z = Lines[0]->Points[0].Z;
        Max_X = Lines[0]->Points[0].X;
        Max_Y = Lines[0]->Points[0].Y;
        Max_Z = Lines[0]->Points[0].Z;
    }
    else{
        Min_X = Faces[0]->Points[0].X;
        Min_Y = Faces[0]->Points[0].Y;
        Min_Z = Faces[0]->Points[0].Z;
        Max_X = Faces[0]->Points[0].X;
        Max_Y = Faces[0]->Points[0].Y;
        Max_Z = Faces[0]->Points[0].Z;
    }
    //在所有Face3D中逐一点比较，更新包围盒所有坐标最小值和最大值
    for (auto pFace : Faces) {
        for (size_t i = 0; i< 3; i++) {
            Min_X = Min_X < pFace->Points[i].X ? Min_X : pFace->Points[i].X;
            Min_Y = Min_Y < pFace->Points[i].Y ? Min_Y : pFace->Points[i].Y;
            Min_Z = Min_Z < pFace->Points[i].Z ? Min_Z : pFace->Points[i].Z;
            Max_X = Max_X > pFace->Points[i].X ? Max_X : pFace->Points[i].X;
            Max_Y = Max_Y > pFace->Points[i].Y ? Max_Y : pFace->Points[i].Y;
            Max_Z = Max_Z > pFace->Points[i].Z ? Max_Z : pFace->Points[i].Z;
        }
    }
    //在所有Line3D中逐一点比较，更新包围盒所有坐标最小值和最大值
    for (auto pLine : Lines) {
        for (size_t i = 0; i< 2; i++) {
            Min_X = Min_X < pLine->Points[i].X ? Min_X : pLine->Points[i].X;
            Min_Y = Min_Y < pLine->Points[i].Y ? Min_Y : pLine->Points[i].Y;
            Min_Z = Min_Z < pLine->Points[i].Z ? Min_Z : pLine->Points[i].Z;
            Max_X = Max_X > pLine->Points[i].X ? Max_X : pLine->Points[i].X;
            Max_Y = Max_Y > pLine->Points[i].Y ? Max_Y : pLine->Points[i].Y;
            Max_Z = Max_Z > pLine->Points[i].Z ? Max_Z : pLine->Points[i].Z;
        }
    }
    //边长为最大坐标与最小左边之差
    m_BoundBox_X = Max_X - Min_X;
    m_BoundBox_Y = Max_Y - Min_Y;
    m_BoundBox_Z = Max_Z - Min_Z;
    //体积为三边长之积
    m_BoundBox_Vol = m_BoundBox_X * m_BoundBox_X * m_BoundBox_Z;
}
//------------------------------------------------------------------------------
